﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Drawing;
using System.IO;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
//using Microsoft.VisualStudio.Modeling.Diagrams;
//using Microsoft.VisualStudio.Modeling.Shell;

namespace ClickDiag
{
    /// <summary>
    /// Структура описания класса из файла диаграммы
    /// </summary>
    struct ImgClass
    {
        public ImgClass(string iName, string cname, string fname, PointF pos, int iwidth)
        {
            this.idName = iName; this.className = cname; this.position = pos; this.width = iwidth; this.height = 0;
        }

        public void ZeroValues()
        {
            this.className = ""; this.position = new PointF(0.0f, 0.0f); this.width = 0;
        }

        public string Info()
        {
            return "Class name = " + className + " Position = " + position.ToString() + " Width = " + width.ToString();
        }

        public string idName;           // id класса плучается из функции SKUtils
        public string className;        // Полное имя класса 
        public PointF position;         // Позиция класса в изображении
        public float width;             // Ширина изображения класса
        public float height;            // ВЫсота изображения класса
    };


    /// <summary>
    /// Кликабельная диаграмма
    /// </summary>
    public class ClickDiagramm
    {
        /// <summary>
        /// Функция WinApi для получения дескриптора окна рабочего стола
        /// </summary>
        /// <returns>дескриптор окна</returns>
        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
        public static extern IntPtr GetDesktopWindow();

        private string diagram_Name;    // Имя диаграммы
        private string diagram_Path;    // Директория где находится файл
        private string diagram_Maps;    // Набор тегов с координатами и ссылками

        private string projectDirectory;

        /// <summary>
        /// Имя диаграммы
        /// </summary>
        public string DIAG_NAME
        {
            get { return diagram_Name; }
        }

        /// <summary>
        /// Набор тегов с координатами и ссылками
        /// </summary>
        public string DIAG_MAPS
        {
            get { return diagram_Maps; }
        }

        /// <summary>
        /// Конструктор клкабельной диаграммы
        /// </summary>
        /// <param name="diagramPath">Полный путь к файлу диаграммы</param>
        /// <param name="projectDir">Директория проекта SHFB</param>
        public ClickDiagramm(string diagramPath, string projectDir)
        {
            projectDirectory = projectDir;

            FileInfo fi = new FileInfo(diagramPath);

            if (fi.Exists)
            {
                diagram_Name = fi.Name;
                diagram_Path = fi.FullName;
            }
            else
            {
                diagram_Name = null;
                diagram_Path = null;
            }
        }

        /// <summary>
        /// Обработчик фала диаграммы классов. Выделяет все классы диаграммы в массив.
        /// </summary>
        /// <returns>Массив классов диаграммы.</returns>
        private ImgClass[] GetImgClasses()
        {
            List<ImgClass> classImgs = new List<ImgClass>();

            float MULTIPLIER_X;
            float MULTIPLIER_Y;
            float MIN_OFFSET;

            using (Graphics g = System.Drawing.Graphics.FromHwnd(GetDesktopWindow()))
            {
                MULTIPLIER_X = g.DpiX;
                MULTIPLIER_Y = g.DpiY;
                MIN_OFFSET = ((g.DpiX + g.DpiY) / 2) / 10;
            }

            if (!File.Exists(diagram_Path))
                return null;

            using (FileStream fs = new FileStream(diagram_Path, FileMode.Open))
            {
                ImgClass iclass = new ImgClass();
                XmlReader rdr = XmlReader.Create(fs);
                while (rdr.Read())
                {
                    if (rdr.NodeType == XmlNodeType.Element)
                    {
                        if (rdr.Name == "Class" || rdr.Name == "Struct")
                        {
                            iclass.ZeroValues();
                            iclass.className = rdr.GetAttribute("Name");
                            iclass.idName = SKUtils.getIdName(rdr.GetAttribute("Name"));
                        }
                        else if (rdr.Name == "Position")
                        {
                            StringBuilder sb = new StringBuilder();

                            sb.AppendLine(rdr.GetAttribute("X"));
                            sb.Replace(".", ",");
                            iclass.position.X = ((float)Convert.ToDouble(sb.ToString()) * MULTIPLIER_X);
                            sb.Remove(0, sb.Length);
                            //sb.Clear();


                            sb.AppendLine(rdr.GetAttribute("Y"));
                            sb.Replace(".", ",");
                            iclass.position.Y = ((float)Convert.ToDouble(sb.ToString()) * MULTIPLIER_Y);
                            sb.Remove(0, sb.Length);
                            //sb.Clear();

                            sb.AppendLine(rdr.GetAttribute("Width"));
                            sb.Replace(".", ",");
                            iclass.width = ((float)Convert.ToDouble(sb.ToString()) * MULTIPLIER_X);
                            sb.Remove(0, sb.Length);
                            //sb.Clear();

                            string height = rdr.GetAttribute("Height");
                            if (height != null)
                            {
                                sb.AppendLine(height);
                                sb.Replace(".", ",");
                                iclass.height = ((float)Convert.ToDouble(sb.ToString()) * MULTIPLIER_Y);
                                sb.Remove(0, sb.Length);
                            }

                            classImgs.Add(iclass);
                        }
                    }
                }
                rdr.Close();
            }

            ImgClass[] iclassArray = classImgs.ToArray();

            float xOffset = iclassArray[0].position.X;
            float yOffset = iclassArray[0].position.Y;

            foreach (ImgClass imc in iclassArray)
            {
                if (imc.position.X < xOffset)
                    xOffset = imc.position.X;
                if (imc.position.Y < yOffset)
                    yOffset = imc.position.Y;
            }

            for (int i = 0; i < iclassArray.Length; i++)
            {
                iclassArray[i].position.X -= (xOffset - MIN_OFFSET);
                iclassArray[i].position.Y -= (yOffset - MIN_OFFSET);
            }

            return iclassArray;
        }

        /// <summary>
        /// Функция получения законченного тега диаграммы для построения карты нажатий.
        /// </summary>
        /// <returns>Тег diagram в текстовом виде</returns>
        public string GetDiagramTag()
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine(@" <diagram imgpath=""..\Diagrams\" + diagram_Name.Remove(diagram_Name.LastIndexOf('.')) + ".jpg" + @""" mapname=""Click_" + diagram_Name.Remove(diagram_Name.LastIndexOf('.')) + @"""> ");

            sb.AppendLine(diagram_Maps);

            sb.AppendLine(@" </diagram>");

            return sb.ToString();
        }

        /// <summary>
        /// Функция проверяет существование класса в диаграмме 
        /// и при положительном результате добавляет тег dimap с координатами класса 
        /// и ссылкой на него в файле документации.
        /// </summary>
        /// <param name="className">Имя класса</param>
        /// <returns>True or False в зависимости от существования класса</returns>
        public bool AddMapTag(string className)
        {
            ImgClass[] imgclss = GetImgClasses();

            if (imgclss == null)
                return false;

            foreach (ImgClass imc in imgclss)
            {
                //// Ссылка на автомат сген топик
                if (className.Trim().Remove(0, 2) == imc.className.Trim())
                {
                    float
                        leftX = 0.0f,
                        leftY = 0.0f,
                        rightX = 0.0f,
                        rightY = 0.0f;

                    // Картинка из Visio
                    if (imc.height != 0)
                    {
                        float offset;

                        using (Graphics g = System.Drawing.Graphics.FromHwnd(GetDesktopWindow()))
                        {
                            offset = ((g.DpiX + g.DpiY) / 2) / 10;
                        }

                        leftX = imc.position.X - offset;
                        leftY = imc.position.Y - offset;

                        rightX = (imc.position.X + imc.width) - offset;
                        rightY = (imc.position.Y + imc.height) - offset;
                    }
                    else // Картинка из VS
                    {
                        leftX = imc.position.X;
                        leftY = imc.position.Y;

                        rightX = imc.position.X + imc.width;
                        rightY = imc.position.Y + 70;
                    }

                    diagram_Maps += @"<dimap coords=""" +
                        Math.Round(leftX).ToString() + @"," +
                        Math.Round(leftY).ToString() + @"," +
                        Math.Round(rightX).ToString() + @"," +
                        Math.Round(rightY).ToString() + @""" href=""" +
                        SKUtils.getIdName(className.Trim()) + @".htm""" + "/>";

                    return true;
                }
                else
                {
                    //// Ссылка на aml топик топик
                    if (className.Trim() == SearchConceptTopic(imc.className))
                    {
                        float
                            leftX = 0.0f,
                            leftY = 0.0f,
                            rightX = 0.0f,
                            rightY = 0.0f;

                        float offset;

                        using (Graphics g = System.Drawing.Graphics.FromHwnd(GetDesktopWindow()))
                        {
                            offset = ((g.DpiX + g.DpiY) / 2) / 10;
                        }

                        leftX = imc.position.X - offset;
                        leftY = imc.position.Y - offset;

                        rightX = (imc.position.X + imc.width) - offset;
                        rightY = (imc.position.Y + imc.height) - offset;

                        diagram_Maps += @"<dimap coords=""" +
                            Math.Round(leftX).ToString() + @"," +
                            Math.Round(leftY).ToString() + @"," +
                            Math.Round(rightX).ToString() + @"," +
                            Math.Round(rightY).ToString() + @""" href=""" +
                            className.Trim() + @".htm""" + "/>";

                        return true;
                    }
                }
            }
            return false;
        }

        private string SearchConceptTopic(string topicName)
        {
            DirectoryInfo di = new DirectoryInfo(projectDirectory);

            if (!di.Exists)
                return null;

            FileInfo[] fis = di.GetFiles("*.aml", SearchOption.AllDirectories);

            foreach (FileInfo f in fis)
                if (f.Name == topicName)
                {
                    XmlReader rdr = XmlReader.Create(f.FullName);
                    while (rdr.Read())
                        if (rdr.Name == "topic")
                            return rdr.GetAttribute("id");
                }

            return null;
        }
    }

}